package com.mecuros.demo.service.impl;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mecuros.common.core.constant.CommonConstants;
import com.mecuros.common.core.constant.enums.MenuTypeEnum;
import com.mecuros.common.core.exception.ErrorCodes;
import com.mecuros.common.core.util.MsgUtils;
import com.mecuros.common.core.util.R;
import com.mecuros.demo.api.dto.UserDTO;
import com.mecuros.demo.api.dto.UserInfo;
import com.mecuros.demo.api.entity.*;
import com.mecuros.demo.api.util.ParamResolver;
import com.mecuros.demo.api.vo.UserExcelVO;
import com.mecuros.demo.api.vo.UserVO;
import com.mecuros.demo.mapper.*;
import com.mecuros.demo.service.SysMenuService;
import com.mecuros.demo.service.SysUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author yujianbo
 * @Classname SysUserServiceImpl
 * @Description TODO
 * @Date 2022/4/17 8:57 下午
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();

    private final SysRoleMapper sysRoleMapper;

    private final SysDeptMapper sysDeptMapper;

    private final SysMenuService sysMenuService;

    private final SysPostMapper sysPostMapper;
//
    private final SysUserRoleMapper sysUserRoleMapper;
//
    private final SysUserPostMapper sysUserPostMapper;

    @Override
    public UserInfo getUserInfo(SysUser sysUser) {
        UserInfo userInfo = new UserInfo();
        userInfo.setSysUser(sysUser);
        // 设置角色列表
        List<SysRole> roleList = sysRoleMapper.listRolesByUserId(sysUser.getUserId());
        userInfo.setRoleList(roleList);
        // 设置角色列表 （ID）
        List<Long> roleIds = roleList.stream().map(SysRole::getRoleId).collect(Collectors.toList());
        userInfo.setRoles(ArrayUtil.toArray(roleIds, Long.class));
        // 设置岗位列表
        List<SysPost> postList = sysPostMapper.listPostsByUserId(sysUser.getUserId());
        userInfo.setPostList(postList);
        // 设置权限列表（menu.permission）
        Set<String> permissions = roleIds.stream().map(sysMenuService::findMenuByRoleId).flatMap(Collection::stream)
                .filter(m -> MenuTypeEnum.BUTTON.getType().equals(m.getType())).map(SysMenu::getPermission)
                .filter(StrUtil::isNotBlank).collect(Collectors.toSet());
        userInfo.setPermissions(ArrayUtil.toArray(permissions, String.class));

        return userInfo;
    }

    @Override
    public IPage<List<UserVO>> getUserWithRolePage(Page page, UserDTO userDTO) {
        return null;
    }

    @Override
    public Boolean removeUserById(SysUser sysUser) {
        return null;
    }

    @Override
    public Boolean updateUserInfo(UserDTO userDto) {
        return null;
    }

    @Override
    public Boolean updateUser(UserDTO userDto) {
        return null;
    }

    @Override
    public UserVO getUserVoById(Long id) {
        return null;
    }

    @Override
    public List<SysUser> listAncestorUsersByUsername(String username) {
        return null;
    }

    /**
     * 保存用户信息
     * @param userDto DTO 对象
     * @return success/fail
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveUser(UserDTO userDto) {
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(userDto,sysUser);
        sysUser.setDelFlag(CommonConstants.STATUS_NORMAL);
        sysUser.setPassword(ENCODER.encode(userDto.getPassword()));
        baseMapper.insert(sysUser);
        userDto.getRole().stream().map(roleId ->{
            SysUserRole userRole = new SysUserRole();
            userRole.setUserId(sysUser.getUserId());
            userRole.setRoleId(roleId);
            return userRole;
        }).forEach(sysUserRoleMapper::insert);
        // 保存用户岗位信息
        Optional.ofNullable(userDto.getPost()).ifPresent(posts ->{
            posts.stream().map(postId -> {
                SysUserPost userPost = new SysUserPost();
                userPost.setUserId(sysUser.getUserId());
                userPost.setPostId(postId);
                return userPost;
            }).forEach(sysUserPostMapper::insert);
        });
        return Boolean.TRUE;
    }

    @Override
    public List<UserExcelVO> listUser(UserDTO userDTO) {
        return null;
    }

    @Override
    public R importUser(List<UserExcelVO> excelVOList, BindingResult bindingResult) {
        return null;
    }

    @Override
    public List<Long> listUserIdByDeptIds(Set<Long> deptIds) {
        return null;
    }

    @Override
    public R<Boolean> registerUser(UserDTO userDto) {
        // 判断用户名是否存在
        SysUser sysUser = this.getOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername, userDto.getUsername()));
        if (sysUser != null) {
            return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_USERNAME_EXISTING, userDto.getUsername()));
        }

        // 获取默认角色编码
        String defaultRole = ParamResolver.getStr("USER_DEFAULT_ROLE");
        // 默认角色
        SysRole sysRole = sysRoleMapper
                .selectOne(Wrappers.<SysRole>lambdaQuery().eq(SysRole::getRoleCode, defaultRole));

        if (sysRole == null) {
            return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_PARAM_CONFIG_ERROR, "USER_DEFAULT_ROLE"));
        }

        userDto.setRole(Collections.singletonList(sysRole.getRoleId()));
        return R.ok(saveUser(userDto));



    }
}
